package handler

import (
	"context"
	"fmt"
	"gitee.com/DonHz/electronic-business-systems/mxshop_srvs/inventory_srv/global"
	"gitee.com/DonHz/electronic-business-systems/mxshop_srvs/inventory_srv/model"
	"gitee.com/DonHz/electronic-business-systems/mxshop_srvs/inventory_srv/proto"
	goredislib "github.com/go-redis/redis/v8"
	"github.com/go-redsync/redsync/v4"
	"github.com/go-redsync/redsync/v4/redis/goredis/v8"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/emptypb"
	"sync"
)

var m sync.Mutex // 这种锁有性能问题，如果请求的不是同一个商品，有点浪费性能

type InventoryServer struct {
	proto.UnimplementedInventoryServer
}

// 设置库存（包括更新）
func (s *InventoryServer) SetInv(ctx context.Context, req *proto.GoodsInvInfo) (*emptypb.Empty, error) {
	var inv model.Inventory
	global.DB.Where(&model.Inventory{Goods: req.GoodsId}).First(&inv)
	inv.Goods = req.GoodsId
	inv.Stocks = req.Num
	global.DB.Save(&inv)
	return &emptypb.Empty{}, nil
}

// 获取库存详情
func (s *InventoryServer) InvDetail(ctx context.Context, req *proto.GoodsInvInfo) (*proto.GoodsInvInfo, error) {
	var inv model.Inventory
	if res := global.DB.Where(&model.Inventory{Goods: req.GoodsId}).First(&inv); res.RowsAffected == 0 {
		return nil, status.Error(codes.NotFound, "库存信息不存在")
	}
	return &proto.GoodsInvInfo{
		GoodsId: inv.Goods,
		Num:     inv.Stocks,
	}, nil
}

// 扣减库存
func (s *InventoryServer) Sell(ctx context.Context, req *proto.SellInfo) (*emptypb.Empty, error) {
	client := goredislib.NewClient(&goredislib.Options{
		Addr: "localhost:16379",
	})
	pool := goredis.NewPool(client)
	rs := redsync.New(pool)

	tx := global.DB.Begin()
	for _, goodInfo := range req.GoodsInfo {
		var inv model.Inventory
		mutexname := fmt.Sprintf("goods_%d", goodInfo.GoodsId)
		mutex := rs.NewMutex(mutexname)

		if err := mutex.Lock(); err != nil {
			tx.Rollback()
			return nil, status.Error(codes.Internal, "获取redis分布式锁异常")
		}
		defer func() {
			if ok, err := mutex.Unlock(); !ok || err != nil {
				tx.Rollback()
				fmt.Printf("释放redis分布式锁异常: %v", err)
			}
		}()
		if res := tx.Where(&model.Inventory{Goods: goodInfo.GoodsId}).First(&inv); res.RowsAffected == 0 {
			tx.Rollback()
			return nil, status.Error(codes.InvalidArgument, "库存信息不存在")
		}
		if inv.Stocks < goodInfo.Num {
			tx.Rollback()
			return nil, status.Error(codes.ResourceExhausted, "库存不足")
		}
		inv.Stocks -= goodInfo.Num
		tx.Save(&inv)
	}
	tx.Commit() //手动提交操作
	return &emptypb.Empty{}, nil
}

// 1订单超时未支付 , 2取消支付, 3订单创建失败-->归还库存
func (s *InventoryServer) Reback(ctx context.Context, req *proto.SellInfo) (*emptypb.Empty, error) {
	// 开启事务
	tx := global.DB.Begin()
	for _, goodInfo := range req.GoodsInfo {
		var inv model.Inventory
		// 这边都是查询操作，可以不用事务
		if res := tx.Where(&model.Inventory{Goods: goodInfo.GoodsId}).First(&inv); res.RowsAffected == 0 {
			tx.Rollback()
			return nil, status.Error(codes.InvalidArgument, "库存信息不存在")
		}

		inv.Stocks += goodInfo.Num
		tx.Save(&inv)
	}
	tx.Commit() //手动提交操作
	return &emptypb.Empty{}, nil
}
